﻿/**
 * Create in 2012-2-6.
 */
package kit4j.view.cs.awt.image.drawer;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

import kit4j.common.converter.Converter;
import kit4j.generator.keyed.IKeyedGenerator;
import kit4j.generator.keyed.RandomPositiveIntegerKeyedGenerator;
import kit4j.generator.keyless.IKeylessGenerator;
import kit4j.generator.keyless.RandomColorKeylessGenerator;
import kit4j.generator.keyless.RandomLogicalFontKeylessGenerator;
import kit4j.view.cs.awt.image.ImageToBufferedImageConverter;

/**
 * 随机风格的字符串绘制器，在指定的图像上绘制随机风格的字符串。
 * 
 * @author MiniKnife
 * 
 */
public class RandomStyleStringDrawer implements IStringDrawer {

	/**
	 * 要绘制的字符串。
	 */
	private String string;

	/**
	 * 验证码字符串与图像边缘的间隔。
	 */
	private Insets margin;

	/**
	 * 验证码字符的字体最大尺寸。
	 */
	private float maxFontSize;

	private IKeylessGenerator<Color> colorGenerator;

	private IKeyedGenerator<Integer, Integer> intGenerator;

	private RandomLogicalFontKeylessGenerator fontGenerator;
	
	private Converter<Image, BufferedImage> imageConverter;

	/**
	 * 创建一个随机风格字符串绘制器。默认的字体最小尺寸为18，最大为32。
	 */
	public RandomStyleStringDrawer() {
		margin = new Insets(0, 0, 0, 0);
		maxFontSize = 32F;

		colorGenerator = new RandomColorKeylessGenerator();
		intGenerator = new RandomPositiveIntegerKeyedGenerator();
		fontGenerator = new RandomLogicalFontKeylessGenerator(18,
				(int) maxFontSize);
	}

	/**
	 * 在指定的图像上以随机风格绘制指定的字符串。<br />
	 * 使用方式为：
	 * 
	 * <pre>
	 * RandomStyleStringDrawer drawer = ...;
	 * Image img = ...;
	 * String str = ...;
	 * drawer.setString(str);
	 * drawer.draw(img);
	 * </pre>
	 * 
	 * 更方便的方式为使用{@link #draw(Image, String) draw(Image, String)}接口。
	 * 
	 * @param img
	 *            要进行绘制的Image对象
	 * @see kit4j.view.cs.awt.image.drawer.IDrawer#draw(java.awt.Image)
	 */
	@Override
	public Image draw(Image img) {
		return draw(img, getString());
	}

	/**
	 * 在指定的图像上以随机风格绘制指定的字符串。<br />
	 * 使用方式为：
	 * 
	 * <pre>
	 * RandomStyleStringDrawer drawer = ...;
	 * Image img = ...;
	 * String str = ...;
	 * drawer.draw(img, str);
	 * </pre>
	 * 
	 * @param img
	 *            要进行绘制的Image对象
	 * @param string
	 *            要绘制的字符串
	 * @return 绘制完成后的图像
	 */
	@Override
	public Image draw(Image img, String string) {
		setString(string);
		
		BufferedImage bufferedImage = convertImageToBufferedImage(img);

		return drawString(bufferedImage);
	}

	/**
	 * 将Image对象转换为BufferedImage对象。
	 * @param img 要转换的Image对象
	 * @return 转换后的BufferedImage对象
	 */
	private BufferedImage convertImageToBufferedImage(Image img) {
		if(img instanceof BufferedImage) {
			return (BufferedImage) img;
		} else {
			Converter<Image, BufferedImage> converter =  getImageConverter();
			
			return converter.convert(img);
		}
	}
	
	/**
	 * 返回图像类型转换器。
	 * @return 图像类型转换器
	 */
	private Converter<Image, BufferedImage> getImageConverter() {
		if(imageConverter == null) {
			imageConverter = new ImageToBufferedImageConverter();
		}
		
		return imageConverter;
	}

	/**
	 * 在图像上绘制字符串。
	 * @param img 要进行绘制的图像
	 * @return 绘制完成后生成的图像
	 */
	private Image drawString(BufferedImage img) {
		Graphics2D g = img.createGraphics();

		// 字符基线坐标与字符间隔值
		float x = getFontBaselineX();
		float y = getFontBaselineY();
		float charSpacing = getCharacterSpacing(img);

		AffineTransform at = new AffineTransform();
		double role; // 旋转角度
		double roleX, roleY = y - maxFontSize / 2;

		for (int i = 0; i < getString().length(); ++i) {

			// 设置文字旋转
			role = (intGenerator.next(21) - 10D) / 10 * Math.PI / 3;
			roleX = x + maxFontSize / 2;
			at.setToRotation(role, roleX, roleY);
			g.setTransform(at);

			// 设置文字颜色
			g.setColor(colorGenerator.next());

			// 设置文字字体
			g.setFont(fontGenerator.next());

			g.drawString(String.valueOf((getString().charAt(i))), x, y);

			x += maxFontSize + charSpacing;
		}

		return img;
	}
	
	/**
	 * 获取字符的基线X轴初始坐标。
	 * @return 基线的X轴坐标
	 */
	private float getFontBaselineX() {
		return margin.left;
	}
	
	/**
	 * 获取字符的基线Y轴初始坐标。
	 * @return 基线的Y轴坐标
	 */
	private float getFontBaselineY() {
		return margin.top + maxFontSize;
	}
	
	/**
	 * 获取字符的间距。
	 * @param img 要绘制的图像
	 * @return 字符间距
	 */
	private float getCharacterSpacing(Image img) {
		return (img.getWidth(null) - margin.left - margin.right - maxFontSize
				* getString().length())
				/ (getString().length() - 1);
	}

	/**
	 * @see kit4j.view.cs.awt.image.drawer.IStringDrawer#getMinFontSize()
	 */
	@Override
	public float getMinFontSize() {
		return fontGenerator.getMinFontSize();
	}

	/**
	 * @see kit4j.view.cs.awt.image.drawer.IStringDrawer#setMinFontSize(float)
	 */
	@Override
	public void setMinFontSize(float fontSize) {
		fontGenerator.setMinFontSize((int) fontSize);
	}

	/**
	 * @see kit4j.view.cs.awt.image.drawer.IStringDrawer#getMaxFontSize()
	 */
	@Override
	public float getMaxFontSize() {
		return maxFontSize;
	}

	/**
	 * @see kit4j.view.cs.awt.image.drawer.IStringDrawer#setMaxFontSize(float)
	 */
	@Override
	public void setMaxFontSize(float fontSize) {
		this.maxFontSize = fontSize;
		fontGenerator.setMaxFontSize((int) fontSize);
	}

	/**
	 * @see kit4j.view.cs.awt.image.drawer.IStringDrawer#getMargin()
	 */
	@Override
	public Insets getMargin() {
		return margin;
	}

	/**
	 * @see kit4j.view.cs.awt.image.drawer.IStringDrawer#setMargin(java.awt.Insets)
	 */
	@Override
	public void setMargin(Insets margin) {
		this.margin = margin;
	}

	/**
	 * @see kit4j.view.cs.awt.image.drawer.IStringDrawer#getString()
	 */
	@Override
	public String getString() {
		return string;
	}

	/**
	 * @see kit4j.view.cs.awt.image.drawer.IStringDrawer#setString(java.lang.String)
	 */
	@Override
	public void setString(String str) {
		this.string = str;
	}

}
